package utils;

import cn.hutool.json.JSONUtil;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author Story
 * @Date 2022/3/27 5:49
 * @Version 1.0
 */
public class BeanRefUtil {


    public static void main(String[] args) {
        List<Map<String, String>> list = new ArrayList<>();
        list.add(new HashMap<String, String>() {{
            put("TIME", "2020-12-22 00:11:11");
            put("VALUE", "12345.45");
            put("TESTBOOLEAN1", "true");
            put("TESTBOOLEAN2", "false");
        }});
        list.add(new HashMap<String, String>() {{
            put("TIME", "2020-12-22 00:12:11");
            put("VALUE", "12222.45");
            put("TESTBOOLEAN1", "false");
            put("TESTBOOLEAN2", "true");
        }});

        List<TestObject> result = new ArrayList<>();
        setFieldValue(TestObject.class, list, result);

        Map<String, String> tempMap = getFieldValueMap(result.get(0));
        System.out.println(JSONUtil.toJsonStr(tempMap));

        System.out.println(getClassTypeValue(String.class,"1"));
    }

    /**
     * 比较另一个对象和当前对象的值
     *
     * @param obj  对象1
     * @param obj2 对象2
     */
    public static Boolean equals(Object obj, Object obj2) {
        if (obj == null && obj2 == null) {
            return true;
        } else if (obj == null || obj2 == null) {
            return false;
        }

        Class<?> clazz = obj.getClass();
        Class<?> clazz2 = obj2.getClass();

        // 俩对象类名不一样
        if (!clazz.getName().equals(clazz2.getName())) {
            return false;
        }

        // 获取所有方法
        Method[] methods = clazz.getDeclaredMethods();
        // 获取所有属性
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            try {
                String fieldName = field.getName();
                String fieldType = field.getType().getSimpleName();
                String fieldGetMethodName = parseGetMethodName(fieldName, fieldType);
                if (!checkGetMethod(methods, fieldGetMethodName)) {
                    continue;
                }
                Method fieldGetMethod = clazz.getMethod(fieldGetMethodName);
                Object fieldVal1 = fieldGetMethod.invoke(obj) == null ? "" : fieldGetMethod.invoke(obj);
                Object fieldVal2 = fieldGetMethod.invoke(obj2) == null ? "" : fieldGetMethod.invoke(obj2);
                if (!fieldVal1.equals(fieldVal2)) {
                    return false;
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     * List<Map<String, String>>数据放入List<Object>中
     *
     * @param objectTypeClass 类对象
     * @param valueMapList    数据
     * @param result          返回的结果集
     */
    public static void setFieldValue(Class<?> objectTypeClass, List<Map<String, String>> valueMapList, List result) {

        // 获取所有方法
        Method[] methods = objectTypeClass.getDeclaredMethods();

        // 获取所有属性
        Field[] fields = objectTypeClass.getDeclaredFields();

        for (Map<String, String> tempMap : valueMapList) {

            try {
                Object bean = objectTypeClass.newInstance();

                for (Field field : fields) {

                    String fieldName = field.getName();
                    String fieldSetMethodName = parseSetMethodName(fieldName);
                    if (fieldSetMethodName == null || !checkSetMethod(methods, fieldSetMethodName)) {
                        continue;
                    }

                    // 该属性类型
                    Class<?> typeClass = field.getType();

                    Method fieldSetMethod = objectTypeClass.getMethod(fieldSetMethodName, typeClass);

                    String value = tempMap.get(fieldName.toUpperCase());

                    if (value != null && !"".equals(value)) {
                        fieldSetMethod.invoke(bean, getClassTypeValue(typeClass, value));
                    }

                }
                result.add(bean);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 取Bean的属性和值对应关系的MAP
     *
     * @param bean
     * @return Map
     */
    public static Map<String, String> getFieldValueMap(Object bean) {
        Map<String, String> result = new HashMap<>();

        Class<?> clazz = bean.getClass();

        // 获取所有方法
        Method[] methods = clazz.getDeclaredMethods();

        // 获取所有属性
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            try {
                String fieldType = field.getType().getSimpleName();
                String fieldGetMethodName = parseGetMethodName(field.getName(), fieldType);
                if (!checkGetMethod(methods, fieldGetMethodName)) {
                    continue;
                }
                Method fieldGetMethod = clazz.getMethod(fieldGetMethodName);
                Object fieldVal = fieldGetMethod.invoke(bean);

                String value = null;
                if ("Date".equals(fieldType)) {
                    value = formatDate((Date) fieldVal);
                } else {
                    if (fieldVal != null) {
                        value = String.valueOf(fieldVal);
                    }
                }
                result.put(field.getName(), value);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * set属性的值到Bean
     *
     * @param bean
     * @param valueMap
     */
    public static void setFieldValue(Object bean, Map<String, String> valueMap) {
        Class<?> clazz = bean.getClass();

        // 获取所有方法
        Method[] methods = clazz.getDeclaredMethods();

        // 获取所有属性
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            try {
                String fieldName = field.getName();
                String fieldSetMethodName = parseSetMethodName(fieldName);
                if (!checkSetMethod(methods, fieldSetMethodName)) {
                    continue;
                }

                // 该属性类型
                Class<?> typeClass = field.getType();

                Method fieldSetMethod = clazz.getMethod(fieldSetMethodName, typeClass);
//                Method fieldSetMethod = clazz.getDeclaredMethod(fieldSetMethodName, new Class[]{typeClass});
                String value = valueMap.get(fieldName.toUpperCase());

                if (value != null && !"".equals(value)) {
                    fieldSetMethod.invoke(bean, getClassTypeValue(typeClass, value));
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 通过class类型获取获取对应类型的值
     *
     * @param typeClass class类型
     * @param value     值
     * @return Object
     */
    private static Object getClassTypeValue(Class<?> typeClass, String value) {
        String fieldType = typeClass.getSimpleName();
        switch (fieldType) {
            case "String":
                return value;
            case "Date":
                return parseDate(value);
            case "Integer":
            case "int":
                return Integer.parseInt(value);
            case "Long":
            case "long":
                return Long.parseLong(value);
            case "Double":
            case "double":
                return Double.parseDouble(value);
            case "Float":
            case "float":
                return Float.parseFloat(value);
            case "Boolean":
            case "boolean":
                return Boolean.parseBoolean(value);
            default:
                return typeClass.cast(value);
        }
    }

    /**
     * 拼接某属性的 get方法
     *
     * @param fieldName
     * @return String
     */
    public static String parseGetMethodName(String fieldName, String fieldType) {
        if (fieldName == null || "".equals(fieldName)) {
            return null;
        }
        StringBuilder methodName = new StringBuilder();
        if ("boolean".equals(fieldType)) {
            methodName.append("is");
        } else {
            methodName.append("get");
        }
        if (fieldName.charAt(0) >= 97 && fieldName.charAt(0) <= 122 &&
                fieldName.charAt(1) >= 65 && fieldName.charAt(1) <= 90) {
            methodName.append(fieldName.charAt(0));
        } else {
            methodName.append(fieldName.substring(0, 1).toUpperCase());
        }
        methodName.append(fieldName.substring(1));
        return methodName.toString();
    }

    /**
     * 拼接在某属性的 set方法
     *
     * @param fieldName
     * @return String
     */
    public static String parseSetMethodName(String fieldName) {
        if (fieldName == null || "".equals(fieldName)) {
            return null;
        }
        StringBuilder methodName = new StringBuilder();
        methodName.append("set");
        if (fieldName.charAt(0) >= 97 && fieldName.charAt(0) <= 122 &&
                fieldName.charAt(1) >= 65 && fieldName.charAt(1) <= 90) {
            methodName.append(fieldName.charAt(0));
        } else {
            methodName.append(fieldName.substring(0, 1).toUpperCase());
        }
        methodName.append(fieldName.substring(1));
        return methodName.toString();
    }

    /**
     * 判断是否存在某属性的 set方法
     *
     * @param methods
     * @param fieldSetMet
     * @return boolean
     */
    public static boolean checkSetMethod(Method[] methods, String fieldSetMet) {
        for (Method met : methods) {
            if (fieldSetMet.equals(met.getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否存在某属性的 get方法
     *
     * @param methods
     * @param fieldGetMet
     * @return boolean
     */
    public static boolean checkGetMethod(Method[] methods, String fieldGetMet) {
        for (Method met : methods) {
            if (fieldGetMet.equals(met.getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 格式化string为Date
     *
     * @param dateStr
     * @return date
     */
    private static Date parseDate(String dateStr) {
        if (dateStr == null || "".equals(dateStr)) {
            return null;
        }
        try {
            String fmtStr;
            if (dateStr.contains(":")) {
                fmtStr = "yyyy-MM-dd HH:mm:ss";
            } else {
                fmtStr = "yyyy-MM-dd";
            }
            SimpleDateFormat sdf = new SimpleDateFormat(fmtStr);
            return sdf.parse(dateStr);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 日期转化为String
     *
     * @param date
     * @return date string
     */
    private static String formatDate(Date date) {
        if (date == null) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.format(date);
        } catch (Exception e) {
            return null;
        }
    }

    static class TestObject {
        private Date time;
        private Float value;
        private Boolean testBoolean1;
        private boolean testBoolean2;

        public Date getTime() {
            return time;
        }

        public void setTime(Date time) {
            this.time = time;
        }

        public Float getValue() {
            return value;
        }

        public void setValue(Float value) {
            this.value = value;
        }

        public Boolean getTestBoolean1() {
            return testBoolean1;
        }

        public void setTestBoolean1(Boolean testBoolean1) {
            this.testBoolean1 = testBoolean1;
        }

        public boolean isTestBoolean2() {
            return testBoolean2;
        }

        public void setTestBoolean2(boolean testBoolean2) {
            this.testBoolean2 = testBoolean2;
        }
    }
}
